/**
 * @fileoverview 错误处理工具模块
 * 提供统一的错误处理、日志记录和错误信息美化功能
 */

import { default as chalk } from "chalk";
import { promises as fs } from "fs";
import { join } from "path";

/**
 * 错误类型枚举
 */
const ErrorType = {
  FILE_SYSTEM: "文件系统错误",
  DEPENDENCY: "依赖安装错误",
  CONFIGURATION: "配置错误",
  NETWORK: "网络错误",
  BUILD: "构建错误",
  UNKNOWN: "未知错误",
};

/**
 * 日志级别枚举
 */
const LogLevel = {
  INFO: "info",
  WARN: "warn",
  ERROR: "error",
  DEBUG: "debug",
};

/**
 * 错误处理类
 */
class ErrorHandler {
  constructor(options = {}) {
    this.logFilePath = options.logFilePath || "arena-project-errors.log";
    this.debug = options.debug || false;
    this.exitOnError =
      options.exitOnError !== undefined ? options.exitOnError : true;
    this.showStackTrace = options.showStackTrace || false;
    this.hasErrors = false; // 追踪是否有错误发生
  }

  /**
   * 格式化时间戳
   * @returns {string} 格式化的时间戳
   */
  getTimestamp() {
    const now = new Date();
    return now.toISOString();
  }

  /**
   * 将日志写入文件
   * @param {string} message - 日志消息
   * @param {string} level - 日志级别
   */
  async writeToLog(message, level = LogLevel.ERROR) {
    // 只有错误级别的日志或者在debug模式下才写入文件
    if (
      level === LogLevel.ERROR ||
      level === LogLevel.WARN ||
      (this.debug && level === LogLevel.DEBUG)
    ) {
      try {
        const logEntry = `[${this.getTimestamp()}] [${level.toUpperCase()}] ${message}\n`;
        await fs.appendFile(this.logFilePath, logEntry);

        // 标记有错误发生
        if (level === LogLevel.ERROR) {
          this.hasErrors = true;
        }
      } catch (err) {
        console.error(chalk.red("无法写入日志文件:"), err.message);
      }
    }
  }

  /**
   * 处理错误
   * @param {Error} error - 错误对象
   * @param {string} type - 错误类型
   * @param {string} context - 错误上下文
   * @param {Function} callback - 回调函数
   */
  async handleError(
    error,
    type = ErrorType.UNKNOWN,
    context = "",
    callback = null
  ) {
    const errorType = ErrorType[type] || ErrorType.UNKNOWN;
    const errorMessage = error instanceof Error ? error.message : String(error);
    const stackTrace = error instanceof Error ? error.stack : "";

    // 构建错误信息
    const formattedError = `错误类型: ${errorType}\n上下文: ${context}\n详情: ${errorMessage}`;

    // 输出到控制台
    console.error(chalk.red("\n✖ 错误发生:"));
    console.error(chalk.red(formattedError));

    if (this.showStackTrace && stackTrace) {
      console.error(chalk.gray("\n堆栈跟踪:"));
      console.error(chalk.gray(stackTrace));
    }

    // 提供修复建议
    const suggestion = this.getSuggestion(type, errorMessage);
    if (suggestion) {
      console.error(chalk.yellow("\n可能的解决方案:"));
      console.error(chalk.yellow(suggestion));
    }

    // 写入日志
    await this.writeToLog(
      `${formattedError}${stackTrace ? `\n堆栈跟踪: ${stackTrace}` : ""}`
    );

    // 执行回调
    if (typeof callback === "function") {
      callback(error);
    }

    // 根据配置退出进程
    if (this.exitOnError) {
      console.error(
        chalk.red("\n由于错误，进程将退出。详细日志已写入 " + this.logFilePath)
      );
      process.exit(1);
    }

    return formattedError;
  }

  /**
   * 根据错误类型和消息提供修复建议
   * @param {string} type - 错误类型
   * @param {string} message - 错误消息
   * @returns {string} 修复建议
   */
  getSuggestion(type, message) {
    switch (type) {
      case "FILE_SYSTEM":
        if (message.includes("ENOENT")) {
          return "文件或目录不存在。请检查路径是否正确，并确保有适当的读写权限。";
        } else if (message.includes("EACCES")) {
          return "权限被拒绝。请检查文件权限，或使用管理员权限运行命令。";
        }
        return "请检查文件路径和权限，确保目标路径可写入。";

      case "DEPENDENCY":
        if (message.includes("ENOENT")) {
          return "命令未找到。请确保 'yarn', 'npm', 或 'pnpm' 已正确安装并配置在系统的 PATH 环境变量中。";
        }
        if (
          message.includes("npm ERR") ||
          message.includes("yarn ERR") ||
          message.includes("pnpm ERR")
        ) {
          return "依赖安装失败。尝试以下步骤:\n1. 检查网络连接\n2. 尝试使用 'npm cache clean --force'\n3. 检查package.json格式是否正确\n4. 尝试使用其他NPM镜像: 'npm config set registry https://registry.npmmirror.com/'";
        }
        return "依赖安装失败。请检查网络连接，确保NPM配置正确。";

      case "CONFIGURATION":
        return "配置错误。请检查配置文件格式是否正确，所有必需字段是否存在。";

      case "NETWORK":
        return "网络错误。请检查网络连接，确保能够访问相关服务器。如果使用代理，请检查代理设置。";

      case "BUILD":
        return "构建失败。请检查源代码是否有语法错误，确保所有依赖都已正确安装。";

      default:
        return "请尝试重新运行命令，或查看文档了解更多信息。";
    }
  }

  /**
   * 记录信息日志
   * @param {string} message - 日志消息
   * @param {string} context - 日志上下文
   */
  async logInfo(message, context = "") {
    console.log(
      chalk.blue(`[信息] ${context ? `[${context}] ` : ""}${message}`)
    );

    // 只在调试模式下记录信息日志
    if (this.debug) {
      await this.writeToLog(
        `${context ? `[${context}] ` : ""}${message}`,
        LogLevel.INFO
      );
    }
  }

  /**
   * 记录警告日志
   * @param {string} message - 日志消息
   * @param {string} context - 日志上下文
   */
  async logWarning(message, context = "") {
    console.warn(
      chalk.yellow(`[警告] ${context ? `[${context}] ` : ""}${message}`)
    );
    await this.writeToLog(
      `${context ? `[${context}] ` : ""}${message}`,
      LogLevel.WARN
    );
  }

  /**
   * 记录调试日志
   * @param {string} message - 日志消息
   * @param {string} context - 日志上下文
   */
  async logDebug(message, context = "") {
    if (this.debug) {
      console.debug(
        chalk.gray(`[调试] ${context ? `[${context}] ` : ""}${message}`)
      );
      await this.writeToLog(
        `${context ? `[${context}] ` : ""}${message}`,
        LogLevel.DEBUG
      );
    }
  }
}

// 导出默认错误处理实例
const errorHandler = new ErrorHandler();

export { errorHandler, ErrorHandler, ErrorType, LogLevel };
